#include "version_bc.h"
#include <stdint.h>
#include "cJSON.h"
#include "string.h"

int pairing_code_check(struct broadcast_handle *bc, int code) {
    #ifdef BROADCAST_DEBUG
    printf("remote with code: %d\n", code);
    #endif
    if (!bc->paring_code.enable || code != bc->paring_code.code) return -1;
    else return 0;
}

int versionbc_1_x_x(struct broadcast_handle *bc, cJSON *root, int sub, int update) {
    cJSON *tmp = NULL;

    switch (sub) {
    case 0:
        if (bc->paring_code.enable || bc->verified) return -1;
        break;

    default:
    case 2:
    case 1:
        tmp = cJSON_GetObjectItemCaseSensitive(root,"code");
        if ((!tmp && bc->paring_code.enable) || (tmp && pairing_code_check(bc, tmp->valueint)==-1)) {
            return -1;
        }
        tmp = cJSON_GetObjectItemCaseSensitive(root,"userData");
        if(bc->verified) {
            if(bc->verified(tmp?tmp->valuestring:NULL, bc->verifyArg) == false) return -1;
        } else if (tmp) {
            return -1;
        }
        break;
    }
    return 0;
}


static int my_atoi(char *v) {
    int r = 0;
    while (*v >= '0' && *v <= '9') {
        r+=*v-'0';
        v++;
    }
    return r;
}

int version_get(char *ver, int *mainv, int *sub, int *update) {
    int m, s, u;

    if ((ver = strstr(ver, "v"))) m = my_atoi(ver+1);
    else return -1;
    if ((ver = strstr(ver, "."))) s = my_atoi(ver+1);
    else return -1;
    if ((ver = strstr(ver + 1, "."))) u = my_atoi(ver+1);
    else return -1;

    if (mainv) *mainv = m;
    if (sub) *sub = s;
    if (update) *update = u;
    return m*10000 + s*100 + u;
    // 1.1.2 ==> 10102
}

int versionbc_verify(struct broadcast_handle *bc, char *buf, struct broadcast_remote_info *info) {
    cJSON *root = cJSON_Parse(buf);
    if(!root) return -1;

    int mainv, sub, update, type;
    cJSON *j_temp;
    // verison verify
    j_temp = cJSON_GetObjectItemCaseSensitive(root, "version_bc");
    if (!j_temp || !j_temp->valuestring) goto __err;
    version_get(j_temp->valuestring, &mainv, &sub, &update);
    #ifdef BROADCAST_DEBUG
    printf("remote version: %s\n", j_temp->valuestring);
    printf("mainv %d, sub %d, update %d \n", mainv, sub, update);
    #endif
    switch (mainv) {
    case 1:
        if(versionbc_1_x_x(bc, root, sub, update)) goto __err;
        break;
    
    default:
        #ifdef BROADCAST_DEBUG
        printf("remote version unkown: %s\n", j_temp->valuestring);
        #endif    
        goto __err;
    }

    // public field
    j_temp = cJSON_GetObjectItemCaseSensitive(root, "mode");
    if(!j_temp && j_temp->valueint != bc->mode) {
        goto __err;
    }
    j_temp = cJSON_GetObjectItemCaseSensitive(root, "type");
    if(!j_temp) {
        goto __err;
    }
    type = j_temp->valueint;
    if( (bc->type==B_TYPE_CLIENT && type==B_TYPE_CLIENT) ||
        (bc->type==B_TYPE_SERVER && type==B_TYPE_SERVER))
    {
        goto __err;
    }
    j_temp = cJSON_GetObjectItemCaseSensitive(root, "name");
    if (j_temp && j_temp->valuestring) {
        strncpy(info->name, j_temp->valuestring, sizeof(info->name));
        info->name[sizeof(info->name)-1] = 0;
    } else {
        info->name[0] = 0;
    }


    strncpy(bc->version, cJSON_GetObjectItem(root,"version_bc")->string, sizeof(bc->version));
    cJSON_Delete(root);
    return 0;

    __err:
    cJSON_Delete(root);
    return -1;
}
